#include "fbdev.h"
#include <linux/fb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <cstdio>
#include <unistd.h>
#include <cstdlib>
#include <sys/mman.h>

fbdev::fbdev(const char* dev)
{
    // 禁止光标闪烁
    FILE* fp = fopen("/sys/class/graphics/fbcon/cursor_blink", "r+");
    fprintf(fp, "0");
    fclose(fp);

    struct fb_var_screeninfo vinfo;
    fd = open(dev, O_RDWR);
    if (fd < 0)
    {
        perror(dev);
    }
    
    if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) < 0)
    {
        perror("FBIOGET_VSCREENINFO");
    }

    width = vinfo.xres;
    height = vinfo.yres;
    bpp = vinfo.bits_per_pixel;
    buf = mmap(NULL, width * height * (bpp >> 3), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (buf == MAP_FAILED)
    {
        perror("mmap");
    }
};

fbdev::~fbdev(void)
{
    munmap(buf, width * height * (bpp >> 3));
    close(fd);
    // 恢复光标闪烁
    FILE* fp = fopen("/sys/class/graphics/fbcon/cursor_blink", "r+");
    fprintf(fp, "1");
    fclose(fp);
};

void fbdev::draw(int x, int y, int color)
{
    int offset = x + y * width;
    int* p = (int*)buf + offset;
    *p = color;
}

void fbdev::clear(int color)
{
    for (int i = 0; i < width * height; i++)
    {
        draw(i % width, i / width, color);
    }
}

void fbdev::show(cv::Mat& img)
{
    cv::Mat frame;

    cv::resize(img, frame, cv::Size(width, height));
    cv::cvtColor(frame, frame, cv::COLOR_BGR2BGRA);
    memcpy(buf, frame.data, frame.total() * frame.elemSize());
}
